package com.triptogether.utils.db;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import android.content.Context;
import android.content.Intent;

import com.triptogether.receivers.MessageCreatedReceiver;
import com.triptogether.receivers.TripCreatedReceiver;
import com.triptogether.utils.db.models.Message;
import com.triptogether.utils.db.models.Product;
import com.triptogether.utils.db.models.ShoppingList;
import com.triptogether.utils.db.models.Trip;
import com.triptogether.utils.db.models.User;
import com.triptogether.utils.log.Logger;

public class DBManager {
	
	private String TAG = Logger.makeLogTag(getClass());
	
	private static DBManager instance;
	private DBHelper helper;
	private Context context;

	public static DBManager getInstance(Context context) {
		if (instance == null) {
			instance = new DBManager(context);
		}
		return instance;
	}

	private DBManager(Context context) {
		this.context = context;
		helper = new DBHelper(context);
	}

	// /////////////////////////////////////////
	// Users Functions
	// /////////////////////////////////////////

	public User createUser(User user) {
		try {
			helper.getUsersDao().create(user);
		} catch (SQLException e) {
			Logger.LOGE(TAG, e.getMessage(), e);
			return null;
		}

		return user;
	}

	public User createUser(String facebookId, String userName) {
		User newUser = new User();
		newUser.setUserName(userName);
		newUser.setFacebookId(facebookId);

		createUser(newUser);

		return newUser;
	}

	public User findUserByFacebookId(String facebookId) {
		User user = null;
		try {
			user = helper.getUsersDao().queryBuilder().where().eq(
			        User.FACEBOOK_ID_COLUMN, facebookId).queryForFirst();
		} catch (SQLException e) {
			Logger.LOGE(TAG, e.getMessage(), e);
		}

		return user;
	}

	public List<User> findRecentUsersChatWith() {
		List<User> usersChatWith = new ArrayList<User>();

		try {
			List<Message> messagesGroupByUsers = helper.getMessagesDao().queryBuilder().groupBy(
			        Message.CHATTER_USER_COLUMN).query();
			for (Message message : messagesGroupByUsers) {
				usersChatWith.add(message.getUserChatWith());
			}
		} catch (SQLException e) {
			Logger.LOGE(TAG, e.getMessage(), e);
		}

		return usersChatWith;
	}

	// /////////////////////////////////////////
	// End of Users Functions
	// /////////////////////////////////////////

	// /////////////////////////////////////////
	// Messages Functions
	// /////////////////////////////////////////
	
	public Message findMessageById(long messageId) {
		Message messageById = null;
		
		try {
	        messageById = helper.getMessagesDao().queryForId(messageId);
        } catch (SQLException e) {
        	Logger.LOGE(TAG, e.getMessage(), e);
        }
		
		return messageById;
	}

	public List<Message> findMessagesFromUser(User fromUserFacebookId) {
		List<Message> allMessageFromUser = new ArrayList<Message>();
		try {
			allMessageFromUser = helper.getMessagesDao().queryBuilder().orderBy(
			        Message.MESSAGE_ID_COLUMN, true).where().eq(
			        Message.CHATTER_USER_COLUMN, fromUserFacebookId.getId()).query();
		} catch (SQLException e) {
			Logger.LOGE(TAG, e.getMessage(), e);
		}
		return allMessageFromUser;
	}

	public Message createMessage(Boolean isFromMe, User otherUser, String message, Date receivedDate) {
		// Create new Message instance
		Message newMessage = new Message();
		newMessage.setUserChatWith(otherUser);
		newMessage.setFromMe(isFromMe);
		newMessage.setMessageText(message);
		newMessage.setDateReceived(receivedDate);

		try {
			helper.getMessagesDao().create(newMessage);
			
			Intent messageCreatedIntent = new Intent(MessageCreatedReceiver.INTENT_FILTER_ACTION_MESSAGE_CREATED);
			messageCreatedIntent.putExtra(MessageCreatedReceiver.INTENT_MESSAGE_CREATE_KEY_MESSAGE_ID, newMessage.getId());
			context.sendBroadcast(messageCreatedIntent);
		} catch (SQLException e) {
			Logger.LOGE(TAG, e.getMessage(), e);
		}

		return newMessage;
	}

	// /////////////////////////////////////////
	// End of Messages Functions
	// /////////////////////////////////////////
	
	// /////////////////////////////////////////
	// Trip Functions
	// /////////////////////////////////////////
	
	private Trip createTrip(Trip newTrip) {
		try {
			helper.getTripDao().create(newTrip);
			
			Intent messageCreatedIntent = new Intent(TripCreatedReceiver.INTENT_FILTER_ACTION_TRIP_CREATED);
			messageCreatedIntent.putExtra(TripCreatedReceiver.INTENT_TRIP_CREATE_KEY_TRIP_ID, newTrip.getId());
			context.sendBroadcast(messageCreatedIntent);
		} catch (SQLException e) {
			Logger.LOGE(TAG, e.getMessage(), e);
		}
		return newTrip;
	}
	
	/**
	 * Create a new trip in the DB with the name and the trip date</br>
	 * return the new Trip object that created in the DB or null if there was an error
	 * @param tripName	The name of the Trip
	 * @param tripDate	The date the trip suppose to be
	 * @return The new Trip that appears in the DB (Id value if filled) or null, if there was an error creating the Trip
	 */
	public Trip createTrip(String tripName, Date tripDate) {
		Trip newTrip = new Trip();
		newTrip.setDateCreated(Calendar.getInstance().getTime());
		newTrip.setTripName(tripName);
		newTrip.setTripDate(tripDate);

		// Create the trip in DB
		return createTrip(newTrip);
	}
	
	public Trip findTripById(long tripId) {
		Trip findTrip = null;
		try {
	        findTrip = helper.getTripDao().queryForId(tripId);
        } catch (SQLException e) {
	        Logger.LOGE(TAG, e.getMessage(), e);
        }
		
		return findTrip;
	}
	
	public List<Trip> findAllTrips() {
		List<Trip> allTrips = new ArrayList<Trip>();
		try {
	        allTrips = helper.getTripDao().queryForAll();
        } catch (SQLException e) {
        	Logger.LOGE(TAG, e.getMessage(), e);
        }
		
		return allTrips;
	}
	
	// /////////////////////////////////////////
	// End of Trip Functions
	// /////////////////////////////////////////
	
	// /////////////////////////////////////////
	// Shopping List Functions
	// /////////////////////////////////////////
	
	public List<ShoppingList> findShoppingListsByTripId(long tripId) {
		List<ShoppingList> allShoppingList = new ArrayList<ShoppingList>();
		try {
			allShoppingList = helper.getShoppingListDao().queryBuilder().where().eq(ShoppingList.TRIP, tripId).query();
		} catch (SQLException e) {
			Logger.LOGE(TAG, e.getMessage(), e);
		}
		
		return allShoppingList;
	}
	
	public ShoppingList findShoppingListById(long shoppingListId) {
		ShoppingList findShoppingList = null;
		try {
	        findShoppingList = helper.getShoppingListDao().queryForId(shoppingListId);
        } catch (SQLException e) {
        	Logger.LOGE(TAG, e.getMessage(), e);
        }
		
		return findShoppingList;
	}

	private ShoppingList createShoppingList(ShoppingList shoppingList) {
		try {
			helper.getShoppingListDao().create(shoppingList);
		} catch (SQLException e) {
			Logger.LOGE(TAG, e.getMessage(), e);
		}

		return shoppingList;
	}

	public ShoppingList createShoppingList(String shoppingListName, Date dateCreated, Trip trip) {
		ShoppingList shoppingList = new ShoppingList();
		shoppingList.setDateCreated(dateCreated);
		shoppingList.setDateModified(dateCreated);
//		shoppingList.setShoppingListName(shoppingListName);
		// TODO: remove this
		shoppingList.setShoppingListName(trip.getTripName() + " " + shoppingListName);
		shoppingList.setTrip(trip);
		
		return createShoppingList(shoppingList);
	}
	
	public ShoppingList createShoppingList(String shoppingListName, Date dateCreated, long tripId) {
		// Find the trip in the DB by its ID
		Trip findTrip = findTripById(tripId);
		
		// Create the shopping list by the trip
		return createShoppingList(shoppingListName, dateCreated, findTrip);
	}

	// ///////////////////////////////////////////////////
	// End of Shopping List Functions
	// ///////////////////////////////////////////////////
	
	// ///////////////////////////////////////////////////
	// Products Functions
	// ///////////////////////////////////////////////////

	public List<Product> findProductsByShoppingListId(long shoppingListId) {
		List<Product> productsByShoppingListId = new ArrayList<Product>();
		try {
			productsByShoppingListId = helper.getProductsDao().queryBuilder().where().eq(
			        Product.SHOPPING_LIST_COLUMN, shoppingListId).query();
		} catch (SQLException e) {
			Logger.LOGE(TAG, e.getMessage(), e);
		}
		return productsByShoppingListId;
	}
	
	private Product createProduct(Product product) {
		try {
			helper.getProductsDao().create(product);
		} catch (SQLException e) {
			Logger.LOGE(TAG, e.getMessage(), e);
		}

		return product;
	}
	
	public Product createProduct(String productName, ShoppingList shoppingList) {
		Product newProduct = new Product();
		newProduct.setBought(false);
		newProduct.setProductName(productName);		
		newProduct.setShoppingList(shoppingList);
		
		return createProduct(newProduct);
	}
	
	public Product createProduct(String productName, long shoppingListId) {
		// Find the shoppingList of the product we create here
		ShoppingList shoppingList = findShoppingListById(shoppingListId);
				
		return createProduct(productName, shoppingList);
	}

	public void updateProduct(Product product) {
		try {
			helper.getProductsDao().update(product);
		} catch (SQLException e) {
			Logger.LOGE(TAG, e.getMessage(), e);
		}
	}

	public void deleteProduct(Product product) {
		try {
			helper.getProductsDao().delete(product);
		} catch (SQLException e) {
			Logger.LOGE(TAG, e.getMessage(), e);
		}
	}
	
	// ///////////////////////////////////////////////////
	// End of Products Functions
	// ///////////////////////////////////////////////////

}
